package org.ala.tiktools.rpc.kcp.protocol.segment;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.util.Recycler;

/**
 * kcp数据段
 *
 * @author ala
 * @date 2025-04-11 09:07
 */
public class KcpSegment {
    /****************************************************************************************************
     *  kcp 数据头部分（24子节）
     ****************************************************************************************************/
    /**
     *  对方标识（4字节 小头序）
     */
    protected int conv;
    /**
     *  指令类型（1字节）
     *  <p> IKCP_CMD_PUSH（请求） | IKCP_CMD_ACP（应答） | IKCP_CMD_WASK（询问窗口） | IKCP_CMD_WINS（回答窗口）
     */
    protected byte cmd;
    /**
     *  消息分段下标（1字节 无符号）
     *  <p> 一个大消息被切成多个段
     */
    protected short frg;
    /**
     *  剩余窗口大小（2字节 无符号，小头序）
     */
    protected int wnd;
    /**
     *  发送时间戳（4字节 小头序）
     */
    protected int ts;
    /**
     *  当前消息的sn号（4字节 无符号 小头序）
     */
    protected long sn;
    /**
     *  期望收到的下个sn号（4字节 无符号 小头序）
     */
    protected long una;
    /**
     *  数据段长度（4字节 小头序）
     */
    protected int len;


    /**
     *  数据段
     */
    protected ByteBuf data;



    /**
     *  消息重发时间戳
     */
    protected int reSendTs;
    /**
     *  消息重试间隔
     */
    protected int rto;
    /**
     *  快速回复标记位
     */
    protected int fastAck;
    /**
     *  重试次数
     */
    protected int xmit;


    /**
     *  回收kcp段
     */
    public void recycle(boolean releaseBuf) {
        conv = 0;
        cmd = 0;
        frg = 0;
        wnd = 0;
        sn = 0;
        una = 0;

        reSendTs = 0;
        fastAck = 0;
        rto = 0;
        xmit = 0;

        if (releaseBuf) {
            data.release();
        }
        data = null;

        recyclerHandle.recycle(this);
    }


    /**
     *  分配
     */
    public static KcpSegment alloc(ByteBuf buf) {
        KcpSegment s = recycler.get();
        s.data = buf;
        return s;
    }
    /**
     *  分配
     */
    public static KcpSegment alloc(ByteBufAllocator allocator, int size) {
        KcpSegment s = recycler.get();
        s.data = size == 0 ? allocator.ioBuffer(0, 0) : allocator.ioBuffer(size);
        return s;
    }
    /**
     *  写入Segment头
     */
    public int writeHead(ByteBuf buf) {
        int offset = buf.writerIndex();
        //  小头序
        buf.writeIntLE(conv);
        buf.writeByte(cmd);
        buf.writeByte(frg);
        buf.writeShortLE(wnd);
        buf.writeIntLE(ts);
        buf.writeIntLE((int) sn);
        buf.writeIntLE((int) una);
        buf.writeIntLE(data == null ? 0 : data.readableBytes());
        return buf.writerIndex() - offset;
    }
    /**
     *  写入完整Segment
     */
    public int writeData(ByteBuf buf) {
        int len = 0;
        if (data != null && data.readableBytes() > 0) {
        	len += data.readableBytes();        	
            buf.writeBytes(data, data.readerIndex(), data.readableBytes());
        }
        return len;
    }
    /**
     *  完整长度
     */
    public int dataLen() {
        return (data == null) ? 0 : data.readableBytes();
    }


    /**
     *  Recycler机制handler
     */
    private final Recycler.Handle<KcpSegment> recyclerHandle;
    /**
     *  线程间共享的对象池（避免频繁gc）
     *  <p> 内部使用Recycler实现，Recycler使每个线程持有一个对象栈，避免锁竞争
     *  <p> 线程间也允许回收其他线程对象到自己的对象栈中
     */
    private static final Recycler<KcpSegment> recycler = new Recycler<KcpSegment>() {
        @Override
        protected KcpSegment newObject(Handle<KcpSegment> handle) {
            return new KcpSegment(handle);
        }
    };
    private KcpSegment(Recycler.Handle<KcpSegment> recyclerHandle) {
        this.recyclerHandle = recyclerHandle;
    }
    /**
     * 	给定长数组用的seg
     */
    public KcpSegment() {
		this.recyclerHandle = null;
    }

    
    public int getConv() {
        return conv;
    }

    public void setConv(int conv) {
        this.conv = conv;
    }

    public byte getCmd() {
        return cmd;
    }

    public void setCmd(byte cmd) {
        this.cmd = cmd;
    }

    public short getFrg() {
        return frg;
    }

    public void setFrg(short frg) {
        this.frg = frg;
    }

    public int getWnd() {
        return wnd;
    }

    public void setWnd(int wnd) {
        this.wnd = wnd;
    }

    public int getTs() {
        return ts;
    }

    public void setTs(int ts) {
        this.ts = ts;
    }

    public long getSn() {
        return sn;
    }

    public void setSn(long sn) {
        this.sn = sn;
    }

    public long getUna() {
        return una;
    }

    public void setUna(long una) {
        this.una = una;
    }

    public int getLen() {
        return len;
    }

    public void setLen(int len) {
        this.len = len;
    }

    public ByteBuf getData() {
        return data;
    }

    public void setData(ByteBuf data) {
        this.data = data;
    }

    public int getReSendTs() {
        return reSendTs;
    }

    public void setReSendTs(int reSendTs) {
        this.reSendTs = reSendTs;
    }

    public int getRto() {
        return rto;
    }

    public void setRto(int rto) {
        this.rto = rto;
    }

    public int getFastAck() {
        return fastAck;
    }

    public void setFastAck(int fastAck) {
        this.fastAck = fastAck;
    }

    public void incrFastAck() {
        this.fastAck++;
    }

    public int getXmit() {
        return xmit;
    }

    public void setXmit(int xmit) {
        this.xmit = xmit;
    }

    public int incrXmit() {
        return ++xmit;
    }
}
